會員系統的部分,我們已經完成第二部分「會員登入」的功能了。接續往「修改會員資料」的功能出發。
在models資料夾新增個login_model.js的檔案。
.
├── app.js
├── bin
│   └── www
├── config
│   └── development_config.js
├── controllers
│   └── modify_controller.js
├── models
│   ├── connection_db.js
│   ├── encryption_model.js
│   ├── login_model.js
│   ├── register_model.js
│   ├── update_model.js
│   └── verification_model.js
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── member.js
│   └── users.js
├── sevice
│   └── member_check.js
├── views
    ├── error.ejs
    └── index.ejs
├── .env
└── .gitignore
從第一個需求推估若要達到這個功能,會員必須要先登入才能進行更換資料的動作。且在上篇文章中,已經實作出token功能。所以我們第一步要先做出能夠驗證會員的功能,也就是看針對token來做個驗證的動作。
在上篇產生token的部分中,我們有故意將id也塞進去。藉由反推token的動作,可以從中取出id,等同於我們只要針對這個id的資料來進行更改動作即可。
首先,我們先寫一個驗證token及透過token來反推id的功能。在models資料夾的verification檔案中寫入:
const jwt = require('jsonwebtoken');
const config = require('../../config/development');
//進行token認證
module.exports = function verifyToken(token) {
    let tokenResult = "";
    const time = Math.floor(Date.now() / 1000);
    return new Promise((resolve, reject) => {
        //判斷token是否正確
        if (token) {
            jwt.verify(token, config.secret, function (err, decoded) {
                if (err) {
                    tokenResult = false;
                    resolve(tokenResult);
                    //token過期判斷
                } else if (decoded.exp <= time) {
                    tokenResult = false;
                    resolve(tokenResult);
                    //若正確
                } else {
                    tokenResult = decoded.data
                    resolve(tokenResult);
                }
            })
        }
    });
}
等同於要是今天token發生錯誤或過期就會回傳false。反之,則回傳反推過後的id值。接續來實作更改會員資料的資料庫功能。
再來接續到controllers資料中的modify_controller.js檔案來新增一個postUpdate的funciton:
postUpdate(req, res, next) {
    const token = req.headers['token'];
    //確定token是否有輸入
    if (check.checkNull(token) === true) {
        res.json({
            err: "請輸入token!"
        })
    } else if (check.checkNull(token) === false) {
        verify(token).then(tokenResult => {
            if (tokenResult === false ) {
                res.json({
                    result: {
                        status: "token錯誤。",
                        err: "請重新登入。"
                    }
                })
            } else {
                res.json({
                    test: "token正確"
                })
            }
        })
    }
}
給予這個API一個新的URL的端口,好讓我們能測試驗證token的部分是否能正常運作。在routes資料夾的member.js檔案中寫入:
var express = require('express');
var router = express.Router();
const MemberModifyMethod = require('../controllers/modify_controller');
memberModifyMethod = new MemberModifyMethod();
router.post('/register', memberModifyMethod.postRegister);
router.post('/login', memberModifyMethod.postLogin);
router.put('/update', memberModifyMethod.putUpdate);
module.exports = router;
來測試看看token是否能正常進行判斷,這邊我們依舊使用Postman來運行。先透過呼叫/login的API來取得token。之後我們在使用token的值來做測試:
loginAPI取得的token值)
發現token偵測後是正確的,且id值也有成功被反推出來。
接續我們嘗試隨便更動token中其中的字母試試看會不會出錯:

其結果是符合我們預期的。
id部分已經在上個動作完成反推動作。接續就實作跟資料庫做聯動的部分:
在models資料夾中新增一個update_model.js的檔案,並寫入:
const db = require('./connection_db');
module.exports = function customerEdit(id, memberUpdateData) {
    let result = {};
    return new Promise((resolve, reject) => {
        db.query('UPDATE member_info SET ? WHERE id = ?', [memberUpdateData, id], function (err, rows) {
            if (err) {
                console.log(err);
                result.status = "會員資料更新失敗。"
                result.err = "伺服器錯誤,請稍後在試!"
                reject(result);
                return;
            }
            result.status = "會員資料更新成功。"
            result.memberUpdateData = memberUpdateData
            resolve(result)
        })
    })
}
接著將controllers資料夾的modify_controller.js檔案中,其putUpdate function修改成:
putUpdate(req, res, next) {
    const token = req.headers['token'];
    //確定token是否有輸入
    if (check.checkNull(token) === true) {
        res.json({
            err: "請輸入token!"
        })
    } else if (check.checkNull(token) === false) {
        verify(token).then(tokenResult => {
            if (tokenResult === false) {
                res.json({
                    result: {
                        status: "token錯誤。",
                        err: "請重新登入。"
                    }
                })
            } else {
                const id = tokenResult;
                
                // 進行加密
                const password = encryption(req.body.password);
                const memberUpdateData = {
                    name: req.body.name,
                    password: password,
                    update_date: onTime()
                }
                updateAction(id, memberUpdateData).then(result => {
                    res.json({
                        result: result
                    })
                }, (err) => {
                    res.json({
                        result: err
                    })
                })
            }
        })
    }
}
接續,我們使用之前第一個成功註冊的會員,其name為test,來進行測試:
先進入/login API來取得token值。待取得後,將token值記錄下來並呼叫/update的API,這部分我們一樣藉由Postman來協助測試,並將其會員的name從test改為test1試試:
loginAPI取得的token值)
修改完成後,我們再到terminal去進到MySQL那邊來輸入select * from member_info;指令,來觀察看看id為1的會員其name值有沒有變成test1。

其結果是有的,代表我們更改會員資料成功。
這在我們已經完成了「修改會員資料」的功能了,接下來我們再來將「會員系統」這部分做個收尾,並添加些不一樣的功能。
token判斷那邊都是resolve,
這樣會沒有rejection的狀態吧?
Hi, ip258852謝謝你的回覆。
是的,token判斷那部分只使用resolve來處理,反倒沒有使用reject。
在「判斷token是否正確」這部分model中verification.js的處理方式為3種情況,分別是:
且都是用promise的resolve方式來進行回傳,並沒有再額外使用reject的方式來回傳錯誤的狀態。
等同於這部分的處理,在controller中modify_controller.js是直接沿用resolve的值來進行更進一步的判斷。
但若是要運用promise的reject的話,寫法就會變成:
const jwt = require('jsonwebtoken');
const config = require('../../config/development');
//進行token認證
module.exports = function verifyToken(token) {
    let tokenResult = '';
    const time = Math.floor(Date.now() / 1000);
    return new Promise((resolve, reject) => {
        //判斷token是否正確
        if (token) {
            jwt.verify(token, config.secret, function (err, decoded) {
                if (err) {
                    reject('token錯誤');
                    //token過期判斷
                } else if (decoded.exp <= time) {
                    reject('token已過期');
                    //若正確
                } else {
                    tokenResult = decoded.data
                    resolve(tokenResult);
                }
            })
        }
    });
}
postUpdate(req, res, next) {
  const token = req.headers['token'];
  //確定token是否有輸入
  if (check.checkNull(token) === true) {
      res.json({
          err: "請輸入token!"
      })
  } else if (check.checkNull(token) === false) {
      verify(token).then(tokenResult => {
        res.json({
          result: {
            status: 'token正確',
          }
        })
      }, (err) => {
        res.json({
          err
        })
      })
  }
}
這樣的寫法也能達到在文章中所提到的效果。
OK 懂了
3Q